#include <stdio.h>
#include <stdlib.h>
#include "slave.h"
#include <assert.h>
#include "args.h"
#include "aceMesh_utils.h"
#include "aceMesh_task.h"
#include "aceMesh_runtime.h"
#include "helper_slave.h"


// __thread_local volatile int buffer_owner[HELPER_BUFFER_COUNT] = {0}; //buffer所有权初始化在主核
volatile unsigned long buffer_owner[HELPER_BUFFER_COUNT] = {0};
__thread_local volatile int buffer_own=0;

volatile struct slave_work_buffer sl_buffers[64][HELPER_BUFFER_COUNT];

__thread_local volatile int own_buf_idx = 0;
volatile new_slave_table tables[64];
// __thread_local_fix volatile int construct_end=0;
volatile unsigned long construct_end=0;
__thread_local volatile int cons_over=0;

volatile int slave_finished[64] = {0}; 

volatile unsigned long slave_exited = 0;
__thread_local volatile int exit_sig=0;


#ifdef MASTER_UNOION_TOP
__thread_local_fix void *local_top1[TOP_WINDOW];
__thread_local_fix volatile int topnum=0;
void *local_task_top[HELPER_NUM][TOP_WINDOW];
#else
extern __thread_local_fix struct top_level_buff tl_buffer[NT];
extern __thread_local_fix volatile int top_sig;
#endif
// __thread_local struct MemPool slave_pool_ldm;
__thread_local_fix int collision_item_count;


// __uncached volatile int slave_init_done=0;

#define remote_ldm(coreid,ldm_var) ((unsigned long)&ldm_var | ((unsigned long)coreid << 20 ) |(1ULL << 45))
#ifdef ACEMESH_GRAPH_BUILD_PROFILING
#ifdef FINE_PROF
// extern double all_pure_register_time[64];
extern double all_pure_addsucc_time[64];
__thread_local_fix double add_succ_start=0.0;
__thread_local_fix double add_succ_end=0.0;

extern double all_pure_register_time[64];
__thread_local_fix double reg_access_start=0.0;
__thread_local_fix double reg_access_end=0.0;

#endif
extern unsigned long buil_prof[N_BUILD_PROF];
// unsigned long add_succ_start;
#endif

#ifdef FLAT_CONSTRUCT_HELEPR
// 计算四个local_task_top子数组的去重并集，并存储在result数组中  
// result数组应该预先分配足够的空间来存储可能的最大并集大小  
int findUnion(void* local_task_top[HELPER_NUM][TOP_WINDOW], void* result[]) {  
    int topSize = 0; // 初始化结果大小为0  
  
    // 四个指针，分别指向四个子数组的当前元素  
    int pointers[HELPER_NUM] = {0};  
    bool hasEnded[HELPER_NUM] = {false}; // 标记每个子数组是否已遍历完  
    while (true) {  
        // 找到当前最小的元素及其索引  
        void* minElement = NULL;  
        // void* minElement = taskBBS[0];  
        int minIndex = -1;  
        for (int i = 0; i < HELPER_NUM; ++i) {  
            if (!hasEnded[i] && (minElement == NULL || local_task_top[i][pointers[i]] < minElement)) {  
                minElement = local_task_top[i][pointers[i]];  
                minIndex = i;  
            }  
        }  
  
        // 如果没有找到最小元素，说明所有子数组都已遍历完  
        if (minElement == NULL) {  
            break;  
        }  
  
        // 将最小元素添加到结果中（如果它还没有被添加过）  
        bool isDuplicate = false;  
        for (int j = 0; j < topSize; ++j) {  
            if (result[j] == minElement) {  
                isDuplicate = true;  
                break;  
            }  
        }  
        if (!isDuplicate) {  
            result[topSize++] = minElement;  
            assert(topSize<=SEND_TASK_WINDOW);
        }  
  
        // 移动找到最小元素的子数组的指针  
        ++pointers[minIndex];  
        assert(minIndex<HELPER_NUM);
        assert(pointers[minIndex]<TOP_WINDOW);
        // 如果该子数组已遍历完，则标记为已结束  
        if (pointers[minIndex] >= TOP_WINDOW || local_task_top[minIndex][pointers[minIndex]] == NULL) {  
            hasEnded[minIndex] = true;  
        }  
    }  
    return topSize;
}  
inline void init_slave_table(int id) {  //初始化
    int i;
    for (i = 0; i < SLAVE_TBL_SIZE; i++) {
        tables[id].items[i].data_addr = NULL;
        tables[id].items[i].data_access =NULL;
        tables[id].items[i].succ = NULL;
    }
    tables[id].col_idx = 0;
    for (i = 0; i < COLLISION_BUF_SIZE; i++) {
        tables[id].col_items[i].data_addr = NULL;
        tables[id].col_items[i].data_access =NULL;
        tables[id].col_items[i].succ = NULL;
    }
}
void init_slave_buffer_and_table(int id) {  //初始化两个buffer的所有权
    int i;
    for (i = 0; i < HELPER_BUFFER_COUNT; i++) {  //buffer数目（HELPER_BUFFER_COUNT）=2
        sl_buffers[id][i].idx = 0;  //idx:当前空位坐标
        buffer_owner[i] = BUF_OWNER_MASTER;  //每个buffer的控制权限初始化在主核
    }

//#ifndef SLAVE_HELPER_WINDOW
    init_slave_table(id);
		// printf("哈希表%d初始化完毕\n",id);
//#endif
}
#endif
// #ifdef DISTRIBUTE_TOP

#ifdef DISTRIBUTE_TOP
#ifndef MASTER_UNOION_TOP
void init_tl_buffer()
{
    int i;
    for(i=0;i<NT;i++){
       tl_buffer[i].head=0;
       tl_buffer[i].tail=0;
    }
}
#endif
#endif
// void init_localtop_buffer(int id)
// {
//     int i;
//     for(i=0;i<NT;i++){
//        local_top[id].top_index=0;
//        local_top[id].top_task[TOP_WINDOW]=NULL;
//     }
// }

// #endif
bool task_exists(struct task** array, int size, struct task* task) {  
    for (int i = 0; i < size; i++) {  
        if (array[i]== task) {  
            return true;  
        }  
    }  
    return false;  
}  

void add_succ(struct DataAccess *succ_access, struct DataAccess *pre_access,int id)

{
#if defined(ACEMESH_GRAPH_BUILD_PROFILING) && defined(FINE_PROF)
    add_succ_start=rtc();
		// unsigned long addsucc_start=rtc();
#endif
     //printf("tbl任务类型%dtblDA地址%p任务地址%ptbl任务地址%p,\n",tbl->data_access->_type,tbl->data_access,data_access->_originator,tbl->data_access->_originator);
    if(pre_access!=NULL){
        if(pre_access->_type==IN && succ_access->_type==IN && pre_access->_accessFlags==SATISFIED){   //识别第一层，前驱是已经就绪的R，新增加剧的R也是自然就绪的，仅连接不阻塞
            slave_set_access_state(SATISFIED, &(succ_access->_accessFlags));
            slave_set_unblock_Successor(pre_access,succ_access); //R1-R2,R1是top，R2为ready					
#ifdef DISTRIBUTE_TOP
						//数据流地址顺序注册，当前是top后面就不会变为succ
	
#ifdef MASTER_UNOION_TOP
        assert(topnum<=TOP_WINDOW);
          local_top1[topnum++]=succ_access->_originator;
#else
       	struct top_level_buff *cur_top=remote_ldm(7,tl_buffer[_MYID]);
		int local_tail=(cur_top->tail+1)%HELPER_BUFF_SIZE; 
              //队列满就一直循环等待
        while(cur_top->head==local_tail){
        }  
        cur_top->top_task[cur_top->tail]=succ_access->_originator;
        cur_top->tail=local_tail;
        // printf("填充%d\n",local_tail);
#endif
        
#endif  
				//  asm volatile ("memb\n");
					 // printf("不阻塞的前驱子任务%p,后继子任务%p\n",predata_access->_originator,data_access->_originator);
         }else { // 以上三个条件，任一不满足，都说明存在实际的依赖（R-W，W-R，W-W，W-R-R），必须修改引用计数
            slave_setSuccessor(pre_access,succ_access);   
						// asm volatile ("memb\n");
           // printf("前驱子任务%p,后继子任务%p\n",predata_access->_originator,data_access->_originator); 
        }   

    }else{
        if(succ_access->_type==IN){ //该地址没有前驱，且类型为读，则设置addr.top=true
            slave_set_access_state(1, &(succ_access->top));
						// asm volatile ("memb\n");
       // printf("设置%p为top%d\n",data_access,data_access->top);
        }
        slave_set_access_state(SATISFIED, &(succ_access->_accessFlags));
#ifdef DISTRIBUTE_TOP
						//数据流地址顺序注册，当前是top后面就不会变为succ
	
#ifdef MASTER_UNOION_TOP
        assert(topnum<=TOP_WINDOW);
          local_top1[topnum++]=succ_access->_originator;
#else
		//将cur_top task发给id+1号从核，让其去识别final top task  
       	struct top_level_buff *cur_top=remote_ldm(7,tl_buffer[_MYID]);
		int local_tail=(cur_top->tail+1)%HELPER_BUFF_SIZE; 
              //队列满就一直循环等待
        while(cur_top->head==local_tail){
        }  
        cur_top->top_task[cur_top->tail]=succ_access->_originator;
        cur_top->tail=local_tail;
        // printf("填充%d\n",local_tail);
#endif
	
#endif 
}
    //printf("设置succ\n");
#if defined(ACEMESH_GRAPH_BUILD_PROFILING) && defined(FINE_PROF)
    //  buil_prof[SUB_ADD_SUCC]+=(rtc()-addsucc_start);
		 add_succ_end=rtc();
		all_pure_addsucc_time[_MYID]+=(double)(add_succ_end-add_succ_start)/SFREQ;
#endif
}

inline struct new_slave_table_item * new_get_collision_buffer_item(int id)
{
    //printf("tables[_MYID]->col_idx %d\n",tables[_MYID]->col_idx );
    assert(tables[id].col_idx  < COLLISION_BUF_SIZE);
       if (tables[id].col_idx >= COLLISION_BUF_SIZE) {
        int i;
        int empty = 0;
        for (i = 0; i < SLAVE_TBL_SIZE; i++) {
            if (tables[id].items[i].data_addr == NULL) {
                empty++;
            }
        }
        printf("empty rate: %f\n", (float)empty / SLAVE_TBL_SIZE);
        fflush(stdout);
        // assert(0);
    }
   struct new_slave_table_item * item = &(tables[id].col_items[tables[id].col_idx]);
    tables[id].col_idx++;
    return item;
}


void worker_help_func()
{
#ifdef DEBUG_PBH
	printf("%dhelper轮询开始\n",_MYID);
  fflush(stdout);

#endif
    int ltid=_MYID%8;
// #ifdef DISTRIBUTE_TOP
// // #ifndef MASTER_UNOION_TOP
// //     init_localtop_buffer(ltid); //初始化latenttop
// // #endif
// #endif
        init_slave_buffer_and_table(_MYID); //初始化哈希表和buffer
		printf("从核%d的哈希表初始完毕\n",_MYID);
		int main_finished = 0;
		slave_work_buffer stack_buf;
		int i,j;
        construct_end=&cons_over; //没有必要放在while循环里，好像放外面也可以
         slave_exited=&exit_sig;
    // latent_top local_top;
 while (1) { //helper一直轮询
        if (cons_over) {
            main_finished = 1;  
            // printf("******主核DFs已经发送完\n");
        }
         buffer_owner[own_buf_idx]=&buffer_own;
        if (buffer_own== BUF_OWNER_SLAVE) {  //buffer权限此时在从核
        // printf("buffer%d权限此时在从核idx\n",_MYID);
            int k = 0;
            slave_helper_item * item = NULL;
            int tbl_idx = 0;
            volatile unsigned long dma_reply = 0;
            athread_get(0, &(sl_buffers[_MYID][own_buf_idx]), &stack_buf, sizeof(slave_work_buffer), (void*)&dma_reply, 0, 0, 0);
            while (dma_reply != 1)
                ;
    // #ifdef SLAVE_HELPER_PROF
    //         update_task += stack_buf.idx;
    // #endif
            printf("buffer%d权限此时在从核idx%d\n",_MYID,stack_buf.idx);
            for (k = 0; k < stack_buf.idx; k++) {
#if defined(ACEMESH_GRAPH_BUILD_PROFILING) && defined(FINE_PROF)
    reg_access_start=rtc();
		unsigned long add_succ_start=rtc();
#endif
                item = &(stack_buf.items[k]);
               // assert(item==NULL);
                // tbl_idx = ((item->hash_value) >> 44) & 0xffff;  //取高20位中的低16位，65536			
                void *address=item->item_address;
                unsigned long hash_value=item->item_hash;
                struct DataAccess *access=item->item_access;
                //assert(access==NULL);
                // int id=item->item_id;
                struct DataAccess *predecessor=NULL;
                    tbl_idx = ((hash_value) >> 44) & 0xffff; ////取高20位(高位的变化更大)中的低16位，65536
                //printf("%p更新DA地址%ptbl地址%p,\n",tbl->data_access,access->_originator,tbl->data_access->_originator);
                if (tables[_MYID].items[tbl_idx].data_addr == address) {  //哈希表存在地址
                            predecessor=tables[_MYID].items[tbl_idx].data_access;
                                slave_add_succ(access, predecessor,ltid);
                                    tables[_MYID].items[tbl_idx].data_access=access; //更新哈希表
                                    asm volatile ("memb\n");
                }
                else if (tables[_MYID].items[tbl_idx].data_addr == NULL) { //哈希表不存在此地址
                        predecessor=tables[_MYID].items[tbl_idx].data_access; //NULL
                        tables[_MYID].items[tbl_idx].data_addr = address;
                        slave_add_succ(access, predecessor,ltid);
                        tables[_MYID].items[tbl_idx].data_access=access; //更新哈希表
                        asm volatile ("memb\n");
                }
                else {
                        //printf("哈希冲突%p\n",address);
                        struct new_slave_table_item * col_item = NULL;
                        struct new_slave_table_item * temp = &(tables[_MYID].items[tbl_idx]);
                        while (temp->succ != NULL) { 
                                //struct new_slave_table_item *temp_item=NULL;
                                //temp_item=temp->succ;
                                if (temp->succ->data_addr == address) {  
                                        predecessor=temp->succ->data_access;
                                        slave_add_succ(access, predecessor,ltid);
                                        temp->succ->data_access=access; //更新哈希表
                                        asm volatile ("memb\n");
                                        goto update_complete;
                                }
                                temp = temp->succ;   
                        
                        }     
                        collision_item_count++; 
                        col_item = new_get_collision_buffer_item(_MYID);    
                        temp->succ = col_item;
                        col_item->data_addr = address;
                        //slave_new_update_hashitem(access, col_item);
                        predecessor=col_item->data_access;
                        slave_add_succ(access, predecessor,ltid); //依赖边追加和前驱计数更新
                        col_item->data_access=access; //更新哈希表
                update_complete:
                        ;
            
                }
               
#if defined(ACEMESH_GRAPH_BUILD_PROFILING) && defined(FINE_PROF)
    buil_prof[SUB_ADD_SUCC]+=(rtc()-add_succ_start);
    reg_access_end=rtc();
    all_pure_register_time[_MYID]+=(double)(reg_access_end-reg_access_start)/SFREQ;
#endif
            }
            //printf("依赖分析结束MYID%dbuffer%down%d\n",_MYID,own_buf_idx,buffer_owner[own_buf_idx]);
            asm volatile ("memb\n");
            //buffer_owner[own_buf_idx] = BUF_OWNER_MASTER;  //分析完512个df之后控制权移交主核
            buffer_own=BUF_OWNER_MASTER;  //分析完512个df之后控制权移交主核
            own_buf_idx = (own_buf_idx + 1) % HELPER_BUFFER_COUNT;  //切换下一个buffer
        }
        else {
            if (main_finished) {  //此时主核没有把权限移交给从核，但是主核已经发完所有的数据流消息
             //到达一个窗口，或者是spawn_and_gout（全部DFs发送完毕）
#ifdef MASTER_UNOION_TOP
             printf("MYID%d往主存ltid%d发latent top,个数%d\n",_MYID,ltid,topnum);
				volatile unsigned long dma_reply = 0;
                int topsize=sizeof(void *)*topnum;
            //  athread_put(0, &(local_top[ltid]), &local_task_top[ltid][0], sizeof(latent_top), (void*)&dma_reply, 0, 0);                
				athread_put(PE_MODE, &(local_top1[0]), &local_task_top[ltid][0], topsize, (void*)&dma_reply, 0, 0);                	
                    while (dma_reply != 1)
                ;  
                //latent top全部写入主存之后
				//printf("_MYID%d号从核latent_top写入主存完成\n",_MYID);

#endif
      

      
        // int flattenedSize[HELPER_NUM]={0};
   
        // // flattenedSize[i] = 0;  
        // int j=0;
        //     while(local_task_top[ltid][j]!=NULL&&j<TOP_WINDOW){
        //         flattenedSize[ltid]++;
        //         j++;
        //     }
            // for(int j=0;j<5;j++){
            //     printf("%p的元素个数##\n", local_top1[j]);
            //     printf("%p的元素个数\n", local_task_top[ltid][j]);
            // }
        
           //printf("%d的元素个数%d\n", ltid,flattenedSize[i]);
  
    

				slave_finished[_MYID] = 1;
                for (i = 8; i < 8+HELPER_NUM; i++) {  //helper已经全部关闭
                    if (slave_finished[i] == 0) {
                        break;
                    }
                }
                if (i == 8+HELPER_NUM) {
#ifndef MASTER_UNOION_TOP
//窗口的df已经分析完毕，可以让7号从核合并top task
         //printf("helper全都分析完本窗口所包含的依赖\n");
         int *top_union=remote_ldm(7,top_sig);
         *top_union=1;
#endif
//重新初始化哈希表
        init_slave_buffer_and_table(_MYID); //初始化哈希表和buffer
    // #ifdef SLAVE_HELPER_PROF
    //                 for (i = 0; i < SLAVE_TBL_SIZE; i++) {
    //                     if (tables[_MYID].items[i].succ != NULL) {
    //                         collision_slot_count++;
    //                     }
    //                 }
    // #endif
#ifndef MASTER_UNOION_TOP
//需要等待7号从核通知已经合并完吗？？？ 好像不需要？？
        //  int *top_union=remote_ldm(7,top_sig);
        //  *top_union=1;
#endif
    // #ifdef SLAVE_HELPER_WINDOW
                    cons_over = 0;
                    slave_finished[_MYID] = 0;
    // #endif
                   
                   
                    exit_sig = 1; 
                    asm volatile ("memb\n");
                   // break;
                }
            }
        }

    }   

}
